package com.star.jersey.mybatisplus.base.core.contract;

import com.star.jersey.mybatisplus.base.core.contract.enums.ResultCode;
import lombok.Data;

import java.io.Serializable;
import java.util.Objects;

/**
 * 统一的接口响应,标准的响应数据结构
 *
 * @param <T>
 */
@Data
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    // 编码：0、请求成功；500、请求成功但服务异常；403、未登录或者token已失效；401、已登录没有权限。
    protected Integer code;
    // 异常编码：10000、请求参数异常；10001、数据库操作异常；10002、接口请求超时；10003、重复/频繁请求。其他由业务方定义，当未定义时，默认400
    protected Integer errCode;
    // 描述
    protected String msg;

    public boolean isSucceed() {
        return Objects.nonNull(this) && Objects.equals(this.getCode(), ResultCode.OK.getCode());
    }

    // 响应数据
    protected T payload;
    private static final R SUCCESS = new R<>();

    public R() {
        this(ResultCode.OK.getCode(), ResultCode.OK.getDesc());
    }

    public R(Integer code, String msg) {
        this(code, code, msg, (T) null);
    }

    public R(Integer code, Integer errCode, String msg) {
        this.code = code;
        this.errCode = errCode;
        this.msg = msg;
    }

    public R(T payload) {
        this(ResultCode.OK.getCode(), ResultCode.OK.getCode(), ResultCode.OK.getDesc(), payload);
    }

    public R(Integer code, Integer errCode, String msg, T payload) {
        this.code = code;
        this.errCode = errCode;
        this.msg = msg;
        this.payload = payload;
    }

    public static <T> R<T> succeed(T payload) {
        return new R(payload);
    }

    public static <T> R<T> ok() {
        return new R<>();
    }

    public static <T> R<T> ok(T payload) {
        return succeed(payload);
    }

    public static <T> R<T> okWithDesc(String msg) {
        return new R(ResultCode.OK.getCode(), msg);
    }

    public static <T> R<T> fail() {
        return fail(ResultCode.FAIL.getCode());
    }

    public static <T> R<T> fail(Integer errCode) {
        return new R(ResultCode.FAIL.getCode(), errCode, ResultCode.FAIL.getDesc());
    }

    public static <T> R<T> fail(String msg) {
        return fail(ResultCode.FAIL.getCode(), msg);
    }

    public static <T> R<T> fail(Integer errCode, String msg) {
        return new R(ResultCode.FAIL.getCode(), errCode, msg);
    }

    public static boolean empty(R<?> r) {
        return Objects.isNull(r) || !Objects.equals(r.getCode(), ResultCode.OK.getCode()) || Objects.isNull(r.getPayload());
    }

    public static <T> R<T> transform(R source) {
        R<T> target = new R();
        target.setCode(source.getCode());
        target.setErrCode(source.getErrCode());
        target.setMsg(source.getMsg());
        return target;
    }
}